1   /*
2    * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package sun.tools.jconsole;
27  
28  import java.awt.*;
29  import java.awt.event.*;
30  import java.io.*;
31  import java.lang.management.*;
32  import java.lang.reflect.*;
33  
34  import javax.swing.*;
35  import javax.swing.border.*;
36  import javax.swing.event.*;
37  import javax.swing.text.*;
38  
39  import java.util.*;
40  import java.util.List;
41  import java.util.concurrent.*;
42  
43  import sun.awt.*;
44  
45  import static sun.tools.jconsole.Formatter.*;
46  import static sun.tools.jconsole.Resources.*;
47  import static sun.tools.jconsole.Utilities.*;
48  
49  
50  @SuppressWarnings("serial")
51  class ClassTab extends Tab implements ActionListener {
52      PlotterPanel loadedClassesMeter;
53      TimeComboBox timeComboBox;
54      private JCheckBox verboseCheckBox;
55      private HTMLPane details;
56      private ClassOverviewPanel overviewPanel;
57      private boolean plotterListening = false;
58  
59      private static final String loadedPlotterKey        = "loaded";
60      private static final String totalLoadedPlotterKey   = "totalLoaded";
61      private static final String loadedPlotterName       = Resources.getText("Loaded");
62      private static final String totalLoadedPlotterName  = Resources.getText("Total Loaded");
63      private static final Color  loadedPlotterColor      = Plotter.defaultColor;
64      private static final Color  totalLoadedPlotterColor = Color.red;
65  
66      private static final String infoLabelFormat = "ClassTab.infoLabelFormat";
67  
68      /*
69        Hierarchy of panels and layouts for this tab:
70  
71          ClassTab (BorderLayout)
72  
73              North:  topPanel (BorderLayout)
74  
75                          Center: controlPanel (FlowLayout)
76                                      timeComboBox
77  
78                          East:   topRightPanel (FlowLayout)
79                                      verboseCheckBox
80  
81              Center: plotterPanel (BorderLayout)
82  
83                          Center: plotter
84  
85              South:  bottomPanel (BorderLayout)
86  
87                          Center: details
88      */
89  
90      public static String getTabName() {
91          return Resources.getText("Classes");
92      }
93  
94      public ClassTab(VMPanel vmPanel) {
95          super(vmPanel, getTabName());
96  
97          setLayout(new BorderLayout(0, 0));
98          setBorder(new EmptyBorder(4, 4, 3, 4));
99  
100         JPanel topPanel     = new JPanel(new BorderLayout());
101         JPanel plotterPanel = new JPanel(new BorderLayout());
102         JPanel bottomPanel  = new JPanel(new BorderLayout());
103 
104         add(topPanel,     BorderLayout.NORTH);
105         add(plotterPanel, BorderLayout.CENTER);
106         add(bottomPanel,  BorderLayout.SOUTH);
107 
108         JPanel controlPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 5));
109         topPanel.add(controlPanel, BorderLayout.CENTER);
110 
111         verboseCheckBox = new JCheckBox(Resources.getText("Verbose Output"));
112         verboseCheckBox.addActionListener(this);
113         verboseCheckBox.setToolTipText(getText("Verbose Output.toolTip"));
114         JPanel topRightPanel = new JPanel();
115         topRightPanel.setBorder(new EmptyBorder(0, 65-8, 0, 70));
116         topRightPanel.add(verboseCheckBox);
117         topPanel.add(topRightPanel, BorderLayout.AFTER_LINE_ENDS);
118 
119         loadedClassesMeter = new PlotterPanel(Resources.getText("Number of Loaded Classes"),
120                                               Plotter.Unit.NONE, false);
121         loadedClassesMeter.plotter.createSequence(loadedPlotterKey,
122                                                   loadedPlotterName,
123                                                   loadedPlotterColor,
124                                                   true);
125         loadedClassesMeter.plotter.createSequence(totalLoadedPlotterKey,
126                                                   totalLoadedPlotterName,
127                                                   totalLoadedPlotterColor,
128                                                   true);
129         setAccessibleName(loadedClassesMeter.plotter,
130                           getText("ClassTab.loadedClassesPlotter.accessibleName"));
131         plotterPanel.add(loadedClassesMeter);
132 
133         timeComboBox = new TimeComboBox(loadedClassesMeter.plotter);
134         controlPanel.add(new LabeledComponent(Resources.getText("Time Range:"),
135                                               getMnemonicInt("Time Range:"),
136                                               timeComboBox));
137 
138         LabeledComponent.layout(plotterPanel);
139 
140         bottomPanel.setBorder(new CompoundBorder(new TitledBorder(Resources.getText("Details")),
141                                                   new EmptyBorder(10, 10, 10, 10)));
142 
143         details = new HTMLPane();
144         setAccessibleName(details, getText("Details"));
145         JScrollPane scrollPane = new JScrollPane(details);
146         scrollPane.setPreferredSize(new Dimension(0, 150));
147         bottomPanel.add(scrollPane, BorderLayout.SOUTH);
148 
149     }
150 
151     public void actionPerformed(ActionEvent ev) {
152         final boolean b = verboseCheckBox.isSelected();
153         workerAdd(new Runnable() {
154             public void run() {
155                 ProxyClient proxyClient = vmPanel.getProxyClient();
156                 try {
157                     proxyClient.getClassLoadingMXBean().setVerbose(b);
158                 } catch (UndeclaredThrowableException e) {
159                     proxyClient.markAsDead();
160                 } catch (IOException ex) {
161                     // Ignore
162                 }
163             }
164         });
165     }
166 
167 
168     public SwingWorker<?, ?> newSwingWorker() {
169         final ProxyClient proxyClient = vmPanel.getProxyClient();
170 
171         if (!plotterListening) {
172             proxyClient.addWeakPropertyChangeListener(loadedClassesMeter.plotter);
173             plotterListening = true;
174         }
175 
176         return new SwingWorker<Boolean, Object>() {
177             private long clCount, cuCount, ctCount;
178             private boolean isVerbose;
179             private String detailsStr;
180             private long timeStamp;
181 
182             public Boolean doInBackground() {
183                 try {
184                     ClassLoadingMXBean classLoadingMBean = proxyClient.getClassLoadingMXBean();
185 
186                     clCount = classLoadingMBean.getLoadedClassCount();
187                     cuCount = classLoadingMBean.getUnloadedClassCount();
188                     ctCount = classLoadingMBean.getTotalLoadedClassCount();
189                     isVerbose = classLoadingMBean.isVerbose();
190                     detailsStr = formatDetails();
191                     timeStamp = System.currentTimeMillis();
192 
193                     return true;
194                 } catch (UndeclaredThrowableException e) {
195                     proxyClient.markAsDead();
196                     return false;
197                 } catch (IOException e) {
198                     return false;
199                 }
200             }
201 
202             protected void done() {
203                 try {
204                     if (get()) {
205                         loadedClassesMeter.plotter.addValues(timeStamp, clCount, ctCount);
206 
207                         if (overviewPanel != null) {
208                             overviewPanel.updateClassInfo(ctCount, clCount);
209                             overviewPanel.getPlotter().addValues(timeStamp, clCount);
210                         }
211 
212                         loadedClassesMeter.setValueLabel(clCount + "");
213                         verboseCheckBox.setSelected(isVerbose);
214                         details.setText(detailsStr);
215                     }
216                 } catch (InterruptedException ex) {
217                 } catch (ExecutionException ex) {
218                     if (JConsole.isDebug()) {
219                         ex.printStackTrace();
220                     }
221                 }
222             }
223 
224             private String formatDetails() {
225                 String text = "<table cellspacing=0 cellpadding=0>";
226 
227                 long time = System.currentTimeMillis();
228                 String timeStamp = formatDateTime(time);
229                 text += newRow(Resources.getText("Time"), timeStamp);
230                 text += newRow(Resources.getText("Current classes loaded"), justify(clCount, 5));
231                 text += newRow(Resources.getText("Total classes loaded"),   justify(ctCount, 5));
232                 text += newRow(Resources.getText("Total classes unloaded"), justify(cuCount, 5));
233 
234                 return text;
235             }
236         };
237     }
238 
239 
240     OverviewPanel[] getOverviewPanels() {
241         if (overviewPanel == null) {
242             overviewPanel = new ClassOverviewPanel();
243         }
244         return new OverviewPanel[] { overviewPanel };
245     }
246 
247     private static class ClassOverviewPanel extends OverviewPanel {
248         ClassOverviewPanel() {
249             super(getText("Classes"), loadedPlotterKey, loadedPlotterName, null);
250         }
251 
252         private void updateClassInfo(long total, long loaded) {
253             long unloaded = (total - loaded);
254             getInfoLabel().setText(getText(infoLabelFormat, loaded, unloaded, total));
255         }
256     }
257 }